# Python3_DataProcFunc.py
# Create By GF 2023-11-14 12:06

# ----------------------------------------------------------------------------------------------------

# 数据处理函数(Data Processing Functions).

# ----------------------------------------------------------------------------------------------------

import numpy
import pandas

# String Function GF Two String Similarity.
def StrFunc_Two_String_Similarity(String_A:str, String_B:str) -> float:

    Word_Of_Chinese:list = [# 省份(Province)
                            "贵州", "陕西", "四川", "云南",

                            # 城市(City)
                            "宝鸡", "成都", "都江堰", "贵阳", "眉山", "乐山", "丽江", "六盘水", "洛阳", "绵阳", "南充",
                            "内江", "彭州", "遂宁",   "万州", "西安", "咸阳", "玉溪", "遵义",

                            # 行政区(District)
                            "高新", "青白江", "青羊", "双流",

                            # 县(County)
                            "大邑", "户县", "华阳", "南部", "郫县", "仁寿", "资中",

                            # 其它(Other)
                            "淳化", "财经", "白云", "广场",   "红宝石", "海福城", "壕沟",   "华为", "虹祥",   "海逸", "锦华",
                            "丽都", "丽苑", "苹果", "水池",   "蜀都",   "蜀汉",   "蜀泰",   "沙湾", "太升路", "图腾", "新城",
                            "人民", "万达", "万国", "犀浦",   "西山",   "形象",   "新中路", "杨凌", "珠海路", "重龙"]
    # ----------------------------------------------
    Copy_String_A = String_A.replace("苹果", "形象").replace("苹果店", "形象")
    Copy_String_B = String_B.replace("苹果", "形象").replace("苹果店", "形象")
    # ----------------------------------------------
    List_Str_A:list = []
    List_Str_B:list = []
    List_Str_A_Length:int = 0
    List_Str_B_Length:int = 0
    # ----------------------------------------------
    for Idx in range(0, len(Word_Of_Chinese)):
        if (Word_Of_Chinese[Idx] in Copy_String_A): # -> Handle String A.
            List_Str_A.append(Word_Of_Chinese[Idx])
            # --------------------------------------
            Copy_String_A = Copy_String_A.replace(Word_Of_Chinese[Idx], str(''))
        # ------------------------------------------
        if (Word_Of_Chinese[Idx] in Copy_String_B): # -> Handle String B.
            List_Str_B.append(Word_Of_Chinese[Idx])
            # --------------------------------------
            Copy_String_B = Copy_String_B.replace(Word_Of_Chinese[Idx], str(''))
    # ----------------------------------------------
    for Word in Copy_String_A: List_Str_A.append(Word)
    for Word in List_Str_A: List_Str_A_Length += len(Word) # -> Total of Characters Number.
    for Word in Copy_String_B: List_Str_B.append(Word)
    for Word in List_Str_B: List_Str_B_Length += len(Word) # -> Total of Characters Number.
    # ----------------------------------------------
    Matched_Char_Num:int = 0
    # ----------------------------------------------
    if (List_Str_A_Length >= List_Str_B_Length):
        for Str in List_Str_B:
            if (Str in List_Str_A): Matched_Char_Num += len(Str) # -> Number of Characters That Can be Matched.
        # ------------------------------------------
        return round(Matched_Char_Num / List_Str_A_Length, 4)
    # ----------------------------------------------
    if (List_Str_A_Length <  List_Str_B_Length):
        for Str in List_Str_A:
            if (Str in List_Str_B): Matched_Char_Num += len(Str) # -> Number of Characters That Can be Matched.
        # ------------------------------------------
        return round(Matched_Char_Num / List_Str_B_Length, 4)
    # ----------------------------------------------
    # End of Function.

# Pandas 删除所有列包含特定字符串值的行.
def DataProcFunc_Pandas_Delete_Rows_By_AllCol_Contains_StrVal(Df:pandas.core.frame.DataFrame, StrVal:str, Exclude:int = 0) -> pandas.core.frame.DataFrame:

    Target:pandas.core.frame.DataFrame = Df
    # ----------------------------------------------
    RowsIndex:list = Target.index
    ColsName:list = Target.columns
    # ----------------------------------------------
    for i in RowsIndex:
        Condition:int = 0
        # ------------------------------------------
        for j in ColsName:
            if Target.loc[i, j] == StrVal: Condition = Condition + 1
        # ------------------------------------------
        if Condition == (len(ColsName) - Exclude): Target = Target.drop(i) # -> 排除日期列, 所以使用 (len(ColsName) - Exclude).
    # ----------------------------------------------
    return Target

# Pandas 生成日期序列DateFrame.
def DataProcFunc_Pandas_Create_Date_Series_DataFrame(Start_Date:str, End_Date:str) -> pandas.core.frame.DataFrame:

    # Examples:
    #
    # >>> DataProcFunc_Pandas_Create_Date_Series_DataFrame("2021-09-01", "2023-09-30")
    #
    # +-----+-----------+-----------+
    # |     |Date       |日期       |
    # +-----+-----------+-----------+
    # |0    |2021-09-01 |2021-09-01 |
    # |1    |2021-09-02 |2021-09-02 |
    # |2    |2021-09-03 |2021-09-03 |
    # |3    |2021-09-04 |2021-09-04 |
    # |4    |2021-09-05 |2021-09-05 |
    # |...  |...        |...        |
    # |755  |2023-09-26 |2023-09-26 |
    # |756  |2023-09-27 |2023-09-27 |
    # |757  |2023-09-28 |2023-09-28 |
    # |758  |2023-09-29 |2023-09-29 |
    # |759  |2023-09-30 |2023-09-30 |
    # +-----+-----------+-----------+

    # normalize=True: 时间参数值正则化到午夜时间戳(最后就直接变成0:00:00, 而不是15:30:00).
    Date_Series = pandas.date_range(start=Start_Date, end=End_Date, normalize=True)
    # ----------------------------------------------
    df = pandas.DataFrame({"Date": Date_Series})
    # ----------------------------------------------
    df["日期"] = df["Date"]
    # ----------------------------------------------
    return df

# Pandas 列名替换字符.
def DataProcFunc_Pandas_Col_Name_Replace(Col_Name:object, Org:str, New:str) -> str:

    Target:str = str('')
    # ----------------------------------------------
    if type(Col_Name) is str: Target = Col_Name
    if type(Col_Name) is int: Target = str(Col_Name)
    if type(Col_Name) is float: Target = str(Col_Name)
    # ----------------------------------------------
    Target = Target.replace(Org, New) # Explain: replace()不会改变原字符串, 需要变量承接其返回值.
    # ----------------------------------------------
    return Target

# Pandas 字符值替换字符.
def DataProcFunc_Pandas_StrVal_Replace(StrVal:object, Org:str, New:str) -> str:

    Target:str = str('')
    # ----------------------------------------------
    if (type(StrVal) is str): Target = StrVal
    if (type(StrVal) is int): Target = str(StrVal)
    if (type(StrVal) is float): Target = str(StrVal)
    # ----------------------------------------------
    Target = Target.replace(Org, New) # Explain: replace()不会改变原字符串, 需要变量承接其返回值.
    # ----------------------------------------------
    return Target

# Pandas 数值形式字符串值尾部清洗.
def DataProcFunc_Pandas_Digit_Form_StrVal_Tail_Wash(String:str) -> str:

    if type(String) is not str: return String
    # ----------------------------------------------
    Digit_Condition:list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
    # ----------------------------------------------
    Str_Copy:str = String
    # ----------------------------------------------
    if (Str_Copy != "\0"):
        if (len(Str_Copy) == 1) and (Str_Copy not in Digit_Condition): return '\0'
        # ------------------------------------------
        while (Str_Copy[-1] not in Digit_Condition): Str_Copy = Str_Copy[0: (len(Str_Copy) - 1)]
        # ------------------------------------------
        return Str_Copy
    else:
        return String
    # ----------------------------------------------
    # Function End.

# Pandas 数值形式字符串或字符串列表取最大值.
def DataProcFunc_Pandas_DigStr_Or_StrList_Max(Obj:object) -> str:

    if (type(Obj) is str): return Obj
    # ----------------------------------------------
    if (Obj != '\0') and (type(Obj) is list):
        Val_List:list = []
        # ------------------------------------------
        for i in Obj:
            if (i != ''): Val_List.append(float(i))
            #Val_List.append(float(i))
        # ------------------------------------------
        return str(max(Val_List))
    # ----------------------------------------------
    # Function End.

# Pandas 数值形式字符串或字符串列表取最小值.
def DataProcFunc_Pandas_DigStr_Or_StrList_Min(Obj:object) -> str:

    if (type(Obj) is str): return Obj
    # ----------------------------------------------
    if (Obj != '\0') and (type(Obj) is list):
        Val_List:list = []
        # ------------------------------------------
        for i in Obj:
            if (i != ''): Val_List.append(float(i))
            #Val_List.append(float(i))
        # ------------------------------------------
        return str(min(Val_List))
    # ----------------------------------------------
    # Function End.

# Pandas 数值形式字符串或字符串列表取平均值.
def DataProcFunc_Pandas_DigStr_Or_StrList_Avg(Obj:object) -> str:

    if (type(Obj) is str): return Obj
    # ----------------------------------------------
    if (Obj != '\0') and (type(Obj) is list):
        Val_List:list = []
        # ------------------------------------------
        for i in Obj:
            if (i != ''): Val_List.append(float(i))
            #Val_List.append(float(i))
        # ------------------------------------------
        return str(sum(Val_List) / len(Val_List))
    # ----------------------------------------------
    # Function End.

# Pandas 字符串值分割为列表并跳过其它类型.
def DataProcFunc_Pandas_StrVal_Split_To_List_Skip_Other(Value:object, Delimiter:str) -> list:

    if type(Value) is not str: return Value
    # ----------------------------------------------
    List:list = []
    # ----------------------------------------------
    if (Value != "\0") and (Delimiter in Value):
        List = Value.split(Delimiter)
        # ------------------------------------------
        return List
    else:
        return Value
    # ----------------------------------------------
    # Function End.

# 判断数字形式字符串中数字的个数.
def DataProcFunc_Judge_DigStr_Digit_Number(String:str) -> int:

    Count:int = 0
    # ----------------------------------------------
    for i in range(0, len(String)):
        if (String[i] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']): Count += 1
    # ----------------------------------------------
    return Count

# 判断字符串是否为日期形式.
def DataProcFunc_Judge_Str_Is_Date_Form(String:str) -> int:

    if (len(String) > 10): return 0
    # ----------------------------------------------
    # Date 形式的字符串中至少包含 6 个数字, 如 "2023/1/1" 其中的 "2", "0", "2", "3", "1", "1".
    # Date 形式的字符串中至多包含 8 个数字, 如 "2023/12/31" 其中的 "2", "0", "2", "3", "1", "2", "3", "1".
    # Date 形式的字符串中至少包含 0 个符号, 如 "20230228".
    # Date 形式的字符串中至多包含 2 个符号, 如 "2023/1/1" 其中的 "/", "/".
    FormDesc:dict = {"Part_Year":0, "Part_Month":0, "Part_Day":0, "Reject":0, "Agree":0}
    DateList:list = []
    DigitNum:int = DataProcFunc_Judge_DigStr_Digit_Number(String)
    # ----------------------------------------------
    if (DigitNum < 6 or 8 < DigitNum): return 0 # -> 如果字符串中包含的数字形式字符少于 6 个或者多于 8 个.
    # ----------------------------------------------
    if ('.' in String):
        DateList = String.split('.') # -> 如果 '.' 存在于字符串中, 则按 '.' 分割为列表.
    elif ('-' in String):
        DateList = String.split('-') # -> 如果 '-' 存在于字符串中, 则按 '-' 分割为列表.
    elif ('/' in String):
        DateList = String.split('/') # -> 如果 '/' 存在于字符串中, 则按 '/' 分割为列表.
    elif ("年" in String) and ("月" in String) and ("日" in String):
        DateList = String.split("年")
        DateList[1:] = DateList[-1].split("月")
        DateList[-1] = DateList[-1].replace("日", str(''))
    else:
        return 0 # -> 如果字符串中不存在日期分隔符.
    # ----------------------------------------------
    if (len(DateList) != 3):
        #FormDesc["Reject"] = 1
        # ------------------------------------------
        return 0
    else:
        FormDesc["Part_Year"] = DataProcFunc_Judge_DigStr_Digit_Number(DateList[0])
        FormDesc["Part_Month"] = DataProcFunc_Judge_DigStr_Digit_Number(DateList[1])
        FormDesc["Part_Day"] = DataProcFunc_Judge_DigStr_Digit_Number(DateList[2])
    # ----------------------------------------------
    if (FormDesc["Part_Year"] == 2) or (FormDesc["Part_Year"] == 4): FormDesc["Agree"] += 1
    if (FormDesc["Part_Month"] == 1) or (FormDesc["Part_Month"] == 2): FormDesc["Agree"] += 1
    if (FormDesc["Part_Day"] == 1) or (FormDesc["Part_Day"] == 2): FormDesc["Agree"] += 1
    # ----------------------------------------------
    if (FormDesc["Agree"] == 3):
        return 1
    else:
        return 0

# 日期形式字符串分隔符计数.
def DataProcFunc_Date_Form_Str_Delimiter_Count(String:str, Delimiter:str) -> int:

    Result:int = 0
    # ----------------------------------------------
    for i in String:
        if i == Delimiter: Result = Result + 1
    # ----------------------------------------------
    return Result
    
# 日期形式字符串末尾清洗.
def DataProcFunc_Date_Form_Str_Tail_Wash(String:str) -> str:

    Str_Copy:str = String
    # ----------------------------------------------
    while (Str_Copy[-1] not in "0123456789"):
        Str_Copy = Str_Copy[0: (len(Str_Copy) - 1)]
    # ----------------------------------------------
    while (DataProcFunc_Date_Form_Str_Delimiter_Count(Str_Copy, '.') >= 3):
        Str_Copy = Str_Copy[0: (len(Str_Copy) - 1)]
    # ----------------------------------------------
    while (DataProcFunc_Date_Form_Str_Delimiter_Count(Str_Copy, '-') >= 3):
        Str_Copy = Str_Copy[0: (len(Str_Copy) - 1)]
    # ----------------------------------------------
    while (DataProcFunc_Date_Form_Str_Delimiter_Count(Str_Copy, '/') >= 3):
        Str_Copy = Str_Copy[0: (len(Str_Copy) - 1)]
    # ----------------------------------------------
    return Str_Copy

# 日期形式字符标准化处理.
def DataProcFunc_Date_Form_Str_Standardization(String:str) -> str:

    Str_Copy:str = String
    # ----------------------------------------------
    # Calling Other Functions: 判断字符串是否为日期形式.
    if DataProcFunc_Judge_Str_Is_Date_Form(Str_Copy) == 1:
        # Calling Other Functions: 日期形式字符串末尾清洗.
        Str_Copy = DataProcFunc_Date_Form_Str_Tail_Wash(Str_Copy)
        # ------------------------------------------
        return Str_Copy
    # ----------------------------------------------
    # Calling Other Functions: 判断字符串是否为日期形式.
    if DataProcFunc_Judge_Str_Is_Date_Form(Str_Copy) == 0:
        return Str_Copy
    
# ----------------------------------------------------------------------------------------------------
# EOF
